package UI;// GLFWWindow.java (渲染窗口封装)

import DataStructure.Model;
import OBJ.*;
import org.joml.Matrix4f;
import org.joml.Vector3f;
import org.joml.Vector4f;
import org.lwjgl.opengl.GL;
import org.lwjgl.opengl.GL11;

import java.io.IOException;
import java.util.concurrent.ConcurrentLinkedQueue;

import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11C.*;
import static org.lwjgl.opengl.GL20C.*;

public class ModelWindow {

    // 着色器
    ModelShaderProgram shader = null ;                                              // 着色器程序

    private Matrix4f view;                                              //视图
    private Matrix4f projection;                                        //投影
    //模型
    public String modelPath;            // 模型路径
    public String name;
    Model model;                        // 模型
    ModelRenderer modelRenderer;        // 模型渲染器
    VoxelLoader voxelLoader;            // 体素加载器

    //更新队列
    ConcurrentLinkedQueue<MaterialUpdateRequest> materialQueue;

    // 窗口
    private long windowHandle;                          // 窗口句柄
    private int width;                                  // 窗口宽度
    private int height;                                 // 窗口高度

    // 旋转和移动
    boolean isRotating = false;                         // 是否正在旋转
    boolean isMoving = false;                           // 是否正在移动
    double lastX = 0;                                   // 上一次鼠标位置
    double lastY = 0;                                   // 上一次鼠标位置
    private float scale = 1.0f;                         // 缩放
    private final Vector3f translation = new Vector3f();// 平移
    private float rotationY = 0.0f;                     // 旋转

    //构造函数
    public ModelWindow(int width, int height, String modelPath, String name, ConcurrentLinkedQueue<MaterialUpdateRequest> materialQueue) {
        this.width = width;
        this.height = height;
        this.modelPath = modelPath;
        this.name = name;
        this.materialQueue = materialQueue;
    }
    //运行
    public void run() throws IOException {
        initGLFW(); // 初始化GLFW
        initGL();   // 初始化OpenGL
        mainLoop(); // 主循环
        cleanup();  // 清理资源
    }
    //初始化GLFW
    private void initGLFW() {
        if (!glfwInit()) {
            throw new IllegalStateException("Unable to initialize GLFW");
        }
        // 配置GLFW
        windowHandle = glfwCreateWindow(width, height, "3D Renderer", 0, 0);// 创建窗口
        glfwMakeContextCurrent(windowHandle); // 设置当前上下文
        glfwSetWindowAspectRatio(windowHandle, width, height);  // 限定窗口长宽比为初始化时的长宽比
        glfwSwapInterval(1); // 垂直同步
        // 设置回调
        glfwSetScrollCallback(windowHandle, this::handleScroll);// 滚轮回调
        glfwSetMouseButtonCallback(windowHandle, this::handleMouseButton);// 鼠标按键回调
        glfwSetFramebufferSizeCallback(windowHandle, this::framebuffer_size_callback);// 窗口大小改变回调
    }
    //初始化OpenGL
    private void initGL() {
        GL.createCapabilities(); // 创建OpenGL上下文
        glEnable(GL_DEPTH_TEST); // 启用深度测试
        glfwShowWindow(windowHandle); // 显示窗口
    }
    //主循环
    private void mainLoop() throws IOException {
        render();   // 初始化模型、着色器、摄像机
        while(!glfwWindowShouldClose(windowHandle) && !Thread.currentThread().isInterrupted() )// 窗口未关闭且线程未中断
        {
            // 更新材质
            if(!materialQueue.isEmpty()){
                updateModelMateria();
            }
            // 渲染指令
            renderFrame();
            // 检查并调用事件，交换缓冲
            glfwPollEvents();
            glfwSwapBuffers(windowHandle);
        }
        // 终止前释放资源
        glfwDestroyWindow(windowHandle);
        glfwTerminate();
    }

    private void updateModelMateria() {
        while (!materialQueue.isEmpty()) {
            MaterialUpdateRequest request = materialQueue.poll();
            for(Model.Material material : model.materials) {
                if (material.name.equals(request.name)) {
                    material.diffuseColor = request.diffuseColor;
                    material.path = request.path;
                    if(material.path!=null)material.loadTexture();
                }
            }
        }
    }


    private void render() throws IOException {
        // 清空颜色缓冲区和深度缓冲区
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        shader = new ModelShaderProgram(FileUtils.loadResource("vertex.glsl"),FileUtils.loadResource("fragment.glsl"));

        // 获取uniform变量的位置
        int objectColorLoc = glGetUniformLocation(shader.programId, "objectColor");
        int lightPosLoc =    glGetUniformLocation(shader.programId, "lightPos");
        int lightColorLoc =  glGetUniformLocation(shader.programId, "lightColor");
        int diffuseColorLoc = glGetUniformLocation(shader.programId, "diffuseColor");
        int useTextureLoc = glGetUniformLocation(shader.programId, "useTexture");

        shader.use();
        glUniform3f(objectColorLoc, 1.0f, 0.5f, 0.2f); // 橙色物体
        glUniform3f(lightPosLoc, 2.0f, 2.0f, 2.0f);     // 光源位置
        glUniform3f(lightColorLoc, 1.0f, 1.0f, 1.0f);   // 白光
        glUniform3f(diffuseColorLoc, 1.0f, 1.0f, 1.0f); // 漫反射颜色
        glUniform1i(useTextureLoc, 0);                   // 不使用纹理
        // 加载模型
        model  = ObjModelLoader.loadModel(modelPath+"\\",name);
        ObjModelLoader.loadMtl(modelPath+"\\",name,model);
        modelRenderer = new ModelRenderer(model);
        // 加载体素
        voxelLoader = new VoxelLoader(model);


        // 设置摄像机参数
        Vector3f cameraPos = new Vector3f(0, 0, 3);
        Vector3f cameraTarget = new Vector3f(0, 0.5f, 0);
        Vector3f cameraUp = new Vector3f(0, 1, 0);

        // 创建摄像机矩阵
        projection = new Matrix4f().perspective(
                (float)Math.toRadians(45.0f),
                800.0f / 600.0f,
                0.1f,
                100.0f
        );
        view = new Matrix4f().lookAt(cameraPos, cameraTarget, cameraUp);
    }

    private void renderFrame() throws IOException {
        processInput(); // 处理输入
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        //更新摄像机位置
        double xpos[] = new double[1];
        double ypos[] = new double[1];
        glfwGetCursorPos(windowHandle, xpos, ypos);
        double xoffset = xpos[0] ;
        double yoffset = ypos[0] ;
        if(isMoving || isRotating) {
            xoffset = xpos[0] - lastX;
            yoffset = ypos[0] - lastY;
        }
        lastX = xpos[0];
        lastY = ypos[0];
        if (isRotating) {
            // 根据xoffset来计算旋转角度
            rotationY += (float) (xoffset * 0.01f);
        }
        if (isMoving) {
            // 根据xoffset和yoffset来计算移动量
            transL(xoffset*1.75, yoffset*1.75);
        }
        // 更新变换矩阵
        Matrix4f modelMatrix = new Matrix4f()
                .translate(translation)
                .rotateY(rotationY)
                .scale(scale);
        shader.setMat4("projection", projection);
        shader.setMat4("view", view);
        shader.setMat4("model", modelMatrix);


        // 渲染模型
        modelRenderer.render(model, shader);
        //绘制包围盒
        printBox();



    }

    // 平移
    private void transL(double deltaX, double deltaY) {
        int[] width = new int[1];
        int[] height = new int[1];
        glfwGetWindowSize(windowHandle, width, height);

        int viewportWidth = width[0];
        int viewportHeight = height[0];

        if (deltaX != 0 || deltaY != 0) {
            float deltaNdcX = (float) (2.0f * deltaX / viewportWidth);
            float deltaNdcY = (float) (-2.0f * deltaY / viewportHeight);
            Vector4f ray_eye = new Vector4f(deltaNdcX, deltaNdcY, 0.0f, 0.0f);
            Matrix4f inverseProjection = new Matrix4f(projection).invert();
            Vector4f ray_clip = new Vector4f();
            inverseProjection.transform(ray_eye, ray_clip);
            Matrix4f inverseView = new Matrix4f(view).invert();
            Vector4f ray_world = new Vector4f();
            inverseView.transform(ray_clip, ray_world);
            translation.add(ray_world.x(), ray_world.y(), 0);
        }
    }

    //重置变换
    public void resetTransform() {
        scale = 1.0f;
        translation.set(0, 0, 0);
        rotationY = 0.0f;
    }


    private void printBox(){
        GL11.glBegin(GL_LINE_LOOP);
        GL11.glVertex3f(voxelLoader.minX, voxelLoader.minY, voxelLoader.minZ);
        GL11.glVertex3f(voxelLoader.maxX, voxelLoader.minY, voxelLoader.minZ);
        GL11.glVertex3f(voxelLoader.maxX, voxelLoader.maxY, voxelLoader.minZ);
        GL11.glVertex3f(voxelLoader.minX, voxelLoader.maxY, voxelLoader.minZ);
        GL11.glEnd();
        GL11.glBegin(GL_LINE_LOOP);
        GL11.glVertex3f(voxelLoader.minX, voxelLoader.minY, voxelLoader.maxZ);
        GL11.glVertex3f(voxelLoader.maxX, voxelLoader.minY, voxelLoader.maxZ);
        GL11.glVertex3f(voxelLoader.maxX, voxelLoader.maxY, voxelLoader.maxZ);
        GL11.glVertex3f(voxelLoader.minX, voxelLoader.maxY, voxelLoader.maxZ);
        GL11.glEnd();
        GL11.glBegin(GL_LINE_LOOP);
        GL11.glVertex3f(voxelLoader.maxX, voxelLoader.minY, voxelLoader.minZ);
        GL11.glVertex3f(voxelLoader.maxX, voxelLoader.minY, voxelLoader.maxZ);
        GL11.glVertex3f(voxelLoader.maxX, voxelLoader.maxY, voxelLoader.maxZ);
        GL11.glVertex3f(voxelLoader.maxX, voxelLoader.maxY, voxelLoader.minZ);
        GL11.glEnd();
        GL11.glBegin(GL_LINE_LOOP);
        GL11.glVertex3f(voxelLoader.minX, voxelLoader.minY, voxelLoader.minZ);
        GL11.glVertex3f(voxelLoader.minX, voxelLoader.minY, voxelLoader.maxZ);
        GL11.glVertex3f(voxelLoader.minX, voxelLoader.maxY, voxelLoader.maxZ);
        GL11.glVertex3f(voxelLoader.minX, voxelLoader.maxY, voxelLoader.minZ);
        GL11.glEnd();
        GL11.glBegin(GL_LINE_LOOP);
        GL11.glVertex3f(voxelLoader.minX, voxelLoader.minY, voxelLoader.minZ);
        GL11.glVertex3f(voxelLoader.maxX, voxelLoader.minY, voxelLoader.minZ);
        GL11.glVertex3f(voxelLoader.maxX, voxelLoader.minY, voxelLoader.maxZ);
        GL11.glVertex3f(voxelLoader.minX, voxelLoader.minY, voxelLoader.maxZ);
        GL11.glEnd();
        GL11.glBegin(GL_LINE_LOOP);
        GL11.glVertex3f(voxelLoader.minX, voxelLoader.maxY, voxelLoader.minZ);
        GL11.glVertex3f(voxelLoader.maxX, voxelLoader.maxY, voxelLoader.minZ);
        GL11.glVertex3f(voxelLoader.maxX, voxelLoader.maxY, voxelLoader.maxZ);
        GL11.glVertex3f(voxelLoader.minX, voxelLoader.maxY, voxelLoader.maxZ);
        GL11.glEnd();
    }


    // 输入处理回调
    private void handleScroll(long window, double xoffset, double yoffset) {
        scale += yoffset * 0.1f;
        scale = Math.max(0.1f, scale);
    }
    private void handleMouseButton(long window, int button, int action, int mods) {
        if (action == GLFW_PRESS) {
            if (button == GLFW_MOUSE_BUTTON_RIGHT) {
                // 右键按下，开始旋转
                isRotating = true;
            } else if (button == GLFW_MOUSE_BUTTON_LEFT) {
                // 左键按下，开始移动
                isMoving = true;
            }
        } else if (action == GLFW_RELEASE) {
            if (button == GLFW_MOUSE_BUTTON_RIGHT) {
                // 右键释放，停止旋转
                isRotating = false;
            } else if (button == GLFW_MOUSE_BUTTON_LEFT) {
                // 左键释放，停止移动
                isMoving = false;
            }
        }
    }
    //窗口大小改变回调
    void framebuffer_size_callback(long windowHandle, int width, int height)
    {
        //保持视口不变
        glViewport(0, 0, width, height);
    }

    //esc退出等
    private void processInput() {
        if (glfwGetKey(windowHandle, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
            glfwSetWindowShouldClose(windowHandle, true);
        }
    }
    //清理
    public void cleanup() {
        glfwDestroyWindow(windowHandle);
        glfwTerminate();
    }
}